#include <cstdlib>
#include <type_traits>
#include <map>
#include <mutex>
#include <unordered_set>
#include <memory>
#include "designM/singleton.hpp"

#include "./memPond.hpp"

namespace wheels{

template< typename TYPE >
class memPool
{
    using type_t = TYPE;
    static_assert( std::is_arithmetic< type_t >::value, "TYPE 必须是算术类型" );

public:
    memPool(  ){}
    ~memPool(){
        for( auto & p : m_ponds__ ){
            p.second.reset();
        }
        m_ponds__.clear();
    }
    /**
     * @brief 注册类型
     * @param size 和类型相关的一个和分页的数量 
     * @param count 内存池大小
     */
    void registerType( size_t size , size_t count = 1024 ) {
        auto ptr = std::make_shared< pond< type_t > >( size, count );
        m_ponds__.emplace( size,ptr );
    }
    /**
     * @brief 调整内存池大小
     * @param size 和类型相关的一个和分页的数量
     * @param newCount 新的内存池大小
     * @return true 调整成功
     * @return false 调整失败
     */
    bool reCount( size_t size, size_t newCount ){
        auto it = m_ponds__.find( size );
        if( it == m_ponds__.end() ){
            return false;
        }
        return it->second->reCount( newCount );
    }
    /**
     * @brief 分配内存
     * @param count 内存块数量
     * @return std::shared_ptr< type_t > 分配的内存块 
     */
    std::shared_ptr< type_t > malloc( size_t size = 1 ){
        auto it = m_ponds__.find( size );
        if( it == m_ponds__.end() ){ 
            // 查找不小于 count 的最接近页大小
            auto best = m_ponds__.lower_bound( size );
            if( best == m_ponds__.end() ){
                // 不存在更大的页，取最大的
                if( m_ponds__.empty() ) return nullptr;
                best = std::prev( m_ponds__.end() );
            }
            return best->second->malloc();
        }
        return it->second->malloc();
    }
    /**
     * @brief 释放内存。将内存返回到没有使用的列表中
     * @param size 和类型相关的一个和分页的数量
     * @param p 要释放的内存块
     */
    bool free( size_t size, std::shared_ptr< type_t > p ){
        if( !p ){
            return false;
        }
        auto it = m_ponds__.find( size );
        if( it == m_ponds__.end() ){
            return false;
        }
        it->second->free( p );
        return true;
    }
private:
    std::map< size_t, std::shared_ptr< pond< type_t > > >          m_ponds__;
};
}
